package com.vf.websocket.service;

import java.lang.reflect.Method;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;

import com.jfinal.kit.JsonKit;
import com.jfinal.kit.StrKit;
import com.jfinal.log.Log;
import com.vf.core.render.RenderBean;
import com.vf.core.util.ReflectUtil;
import com.vf.core.util.UuidUtil;
import com.vf.s.common.model.biz.BizWsLog;
import com.vf.websocket.common.constant.Status;
import com.vf.websocket.common.model.CacheMessage;
import com.vf.websocket.common.model.Message;
import com.vf.websocket.common.model.WebSocketUser;

import net.sf.json.JSONObject;

@ServerEndpoint("/websocket/{auth}/{source}")
public class WebSocketServer {

	protected final Log log = Log.getLog(getClass());
	public static ConcurrentHashMap<Integer, Map<String, WebSocketUser>> sessionMap = new ConcurrentHashMap<Integer, Map<String, WebSocketUser>>();
	public static ConcurrentHashMap<String, List<CacheMessage>> cacheMap = new ConcurrentHashMap<String, List<CacheMessage>>();

	@OnOpen
	public void onOpen(Session session, @PathParam("auth") String auth, @PathParam("source") int source) {

		if (sessionMap.containsKey(source)) {
			Map<String, WebSocketUser> concurrentHashMap = sessionMap.get(source);
			if (concurrentHashMap.containsKey(auth)) {
				concurrentHashMap.get(auth).setSession(session);
				concurrentHashMap.put(auth, concurrentHashMap.get(auth));
			} else {
				WebSocketUser user = new WebSocketUser();
				user.setAuth(auth);
				user.setSession(session);
				user.setSource(source);
				concurrentHashMap.put(auth, user);
			}
			sessionMap.put(source, concurrentHashMap);
			log.info(String.format("WebSocket >> source【%s】有一连接加入！, 当前在线人数为  %s", source, concurrentHashMap.size()));
		} else {
			Map<String, WebSocketUser> concurrentHashMap = new ConcurrentHashMap<String, WebSocketUser>();
			WebSocketUser user = new WebSocketUser();
			user.setAuth(auth);
			user.setSession(session);
			user.setSource(source);
			concurrentHashMap.put(auth, user);
			sessionMap.put(source, concurrentHashMap);
			log.info(String.format("WebSocket >> source【%s】有一连接加入！, 当前在线人数为  %s", source, concurrentHashMap.size()));
		}
	}

	@OnMessage
	public void onMessage(String json, Session session, @PathParam("auth") String auth,
			@PathParam("source") int source) {
		try {
			if (StrKit.isBlank(json)) {
				session.getAsyncRemote().sendText(json);
				return;
			}
			Message message = (Message) JSONObject.toBean(JSONObject.fromObject(json), Message.class);
			if (message == null) {
				sendError(session, json, "消息格式有误!");
				return;
			}
			
			if(StrKit.equals("GET_USERS", message.getCode())) {
				getUsers(session,message.getScope());
				return;
			}
			if(StrKit.equals("GET_USER", message.getCode())) {
				getUser(session,message.getScope(),message.getData().toString());
				return;
			}
			
			send(session, message, json);
		} catch (Exception e) {
			sendError(session, json, e.getMessage());
		}
	}

	@OnError
	public void onError(Session session, Throwable e, @PathParam("auth") String auth, @PathParam("source") int source) {
	}

	@OnClose
	public void onClose(Session session, CloseReason closeReason, @PathParam("auth") String auth,
			@PathParam("source") int source) {
		if (sessionMap.containsKey(source)) {
			Map<String, WebSocketUser> concurrentHashMap = sessionMap.get(source);
			if (concurrentHashMap.containsKey(auth)) {
				concurrentHashMap.remove(auth);
				sessionMap.put(source, concurrentHashMap);
				log.info(String.format("WebSocket >> source【%s】有一连接关闭！, 当前在线人数为  %s", source, concurrentHashMap.size()));
			}
		}
	}

	public void send(Session session, Message message, String json) {
		String senderId = message.getSenderId();
		String receiverId = message.getReceiverId();
		String code = message.getCode();
		int scope = message.getScope();

		if (!StrKit.isBlank(receiverId)) {
			if (!sessionMap.containsKey(scope)) {
				sendError(session, json, "一对一通信，【scope】参数必填！");
			} else {
				if (sessionMap.get(scope).containsKey(receiverId)) {
					oneToOne(sessionMap.get(scope).get(receiverId).getSession(), senderId, receiverId, json, code,
							scope + "");
				} else {
					log.info(String.format("WebSocket >> 【%s】不存在, 发送信息失败！", receiverId));
					// cache(receiverId, json);
				}
			}
			return;
		}

		if (!sessionMap.containsKey(scope)) {
			sendError(session, json, "【scope】参数必填！");
		} else {
			Map<String, WebSocketUser> scopeMap = sessionMap.get(scope);
			for (Map.Entry<String, WebSocketUser> entry : scopeMap.entrySet()) {
				oneToOne(entry.getValue().getSession(), senderId, entry.getValue().getAuth(), json, code, scope + "");
			}
		}
	}

	public void cache(String receiverId, String json) {
		if (cacheMap.containsKey(receiverId)) {
			List<CacheMessage> caches = cacheMap.get(receiverId);
			CacheMessage cache = new CacheMessage();
			cache.setAuth(receiverId);
			cache.setDate(new Date(System.currentTimeMillis()));
			cache.setJson(json);
			caches.add(cache);
			cacheMap.put(receiverId, caches);
		} else {
			List<CacheMessage> caches = new LinkedList<CacheMessage>();
			CacheMessage cache = new CacheMessage();
			cache.setAuth(receiverId);
			cache.setDate(new Date(System.currentTimeMillis()));
			cache.setJson(json);
			caches.add(cache);
			cacheMap.put(receiverId, caches);
		}
	}

	public void oneToOne(Session session, String senderId, String receiverId, String json, String code, String scope) {
		session.getAsyncRemote().sendText(json);
		saveLog(senderId, receiverId, code, scope, json);
	}

	public void sendSuccess(Session session) {
		Message message = new Message();
		message.setCode("MSG_STATUS");

		RenderBean renderBean = new RenderBean();
		renderBean.setCode(Status.SUCCESS);
		renderBean.setMessage(Status.SUCCESS_MSG);
		message.setData(renderBean);
		sendMessage(session, message);
	}

	public void sendError(Session session, String json) {
		Message message = new Message();
		message.setCode("MSG_STATUS");
		RenderBean renderBean = new RenderBean();
		renderBean.setCode(Status.ERROR);
		renderBean.setMessage(Status.ERROR_MSG);
		message.setData(renderBean);
		sendMessage(session, message);
	}

	public void sendError(Session session, String json, String error) {
		Message message = new Message();
		message.setCode("MSG_STATUS");
		RenderBean renderBean = new RenderBean();
		renderBean.setCode(Status.ERROR);
		renderBean.setMessage(error);
		message.setData(renderBean);
		sendMessage(session, message); 
	}

	public void sendMessage(Session session, Message message) {
		try {
			session.getAsyncRemote().sendText(JsonKit.toJson(message));
		} catch (Exception e) {
		}
	}

	public void saveLog(String senderId, String receiverId, String code, String scope, String content) {
		try {
			BizWsLog bizWsLog = new BizWsLog();
			bizWsLog.setId(UuidUtil.getUUID());
			bizWsLog.setCode(code);
			bizWsLog.setContent(content);
			bizWsLog.setReceiverId(receiverId);
			bizWsLog.setSenderId(senderId);
			bizWsLog.setScope(scope);
			bizWsLog.save();
		} catch (Exception e) {
		}
	}

	public void sendCacheMessage(Session session, String auth) {
		if (cacheMap.containsKey(auth)) {
			List<CacheMessage> list = cacheMap.get(auth);
			for (CacheMessage cache : list) {
				session.getAsyncRemote().sendText(cache.getJson());
			}
		}
	}
	
	public void getUsers(Session session,int scope) {
		Message message = new Message();
		message.setCode("GET_USERS");
		RenderBean renderBean = new RenderBean();
		
		if(sessionMap.containsKey(scope)) {
			renderBean.setCode(Status.SUCCESS);
			renderBean.setMessage("成功！");
			renderBean.setData(sessionMap.get(scope));
		}else {
			renderBean.setCode(Status.ERROR);
			renderBean.setMessage("无效【"+scope+"】或此来源用户均不在线！");
		}
		message.setData(renderBean);
		sendMessage(session, message);
	}
	
	
	public void getUser(Session session,int scope,String userId) {
		Message message = new Message();
		message.setCode("GET_USER");
		RenderBean renderBean = new RenderBean();
		
		if(sessionMap.containsKey(scope) && sessionMap.get(scope).containsKey(userId)) {
			renderBean.setCode(Status.SUCCESS);
			renderBean.setMessage("成功！");
			renderBean.setData(sessionMap.get(scope).get(userId));
		}else {
			renderBean.setCode(Status.ERROR);
			renderBean.setMessage("用户不在线！");
		}
		
		message.setData(renderBean);
		sendMessage(session, message);
	}
	
	public static void main(String[] args) {
		try {
			Message message = new Message();
            Class <?> clazz = Class.forName("com.vf.s.mvc.scene.service.SceneLayerService");
			Method method = clazz.getMethod("handle", Message.class);
	        Object obj= method.invoke(clazz.newInstance(), message);  
	        System.out.println(obj);
		}catch (Exception e) {
			e.printStackTrace();
		}
		
	}
	
}
